bitkeeper revision 1.1159.221.1 (41ebbfeezjfpGp20MD6f6Xl2r6Wd3Q)
authorsd386@font.cl.cam.ac.uk <sd386@font.cl.cam.ac.uk>
Mon, 17 Jan 2005 13:38:54 +0000 (13:38 +0000)
committersd386@font.cl.cam.ac.uk <sd386@font.cl.cam.ac.uk>
Mon, 17 Jan 2005 13:38:54 +0000 (13:38 +0000)
Added new simple EDF scheduler

12 files changed:
.rootkeys
tools/libxc/Makefile
tools/libxc/xc.h
tools/libxc/xc_sedf.c [new file with mode: 0644]
tools/python/xen/lowlevel/xc/xc.c
tools/python/xen/xend/XendClient.py
tools/python/xen/xend/XendDomain.py
tools/python/xen/xend/server/SrvDomain.py
tools/python/xen/xm/main.py
xen/common/sched_sedf.c [new file with mode: 0644]
xen/common/schedule.c
xen/include/public/sched_ctl.h

index 1691f867c4f7633ad5a399317f30408d0df2a687..7b301acebb544bf3de6d5a1ab14109dfae961d3f 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c
 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h
 40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c
+41ebbfe9U0b0kI-HgjK7VEY4EvW7_w tools/libxc/xc_sedf.c
 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile
 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c
 40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h
 4064773cJ31vZt-zhbSoxqft1Jaw0w xen/common/sched_atropos.c
 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c
 40589968be_t_n0-w6ggceW7h-sx0w xen/common/sched_rrobin.c
+41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c
 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
 3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c
 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c
index 78ba7f3bf349cdb447c4e0b64d4031dbf367632a..87c8c337ad198b678d671f9e4a7a7c6ca581135e 100644 (file)
@@ -12,6 +12,7 @@ vpath %c       $(XEN_LIBXUTIL)
 INCLUDES += -I $(XEN_LIBXUTIL)
 
 SRCS     :=
+SRCS     += xc_sedf.c
 SRCS     += xc_atropos.c
 SRCS     += xc_bvtsched.c
 SRCS     += xc_domain.c
index 7778b71673e5fbbcac570295ed2c389e45fc9fd2..badfbb375d728abd8041d8d3e307d356d0665727 100644 (file)
@@ -132,6 +132,14 @@ int xc_rrobin_global_set(int xc_handle, u64 slice);
 
 int xc_rrobin_global_get(int xc_handle, u64 *slice);
 
+int xc_sedf_domain_set(int xc_handle,
+                          u32 domid,
+                          u64 period, u64 slice);
+
+int xc_sedf_domain_get(int xc_handle,
+                          u32 domid,
+                          u64* period, u64 *slice);
+
 typedef evtchn_status_t xc_evtchn_status_t;
 int xc_evtchn_alloc_unbound(int xc_handle,
                             u32 dom,
diff --git a/tools/libxc/xc_sedf.c b/tools/libxc/xc_sedf.c
new file mode 100644 (file)
index 0000000..92c052f
--- /dev/null
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * xc_sedf.c
+ * 
+ * API for manipulating parameters of the Simple EDF scheduler.
+ * 
+ * changes by Stephan Diestelhorst
+ * based on code
+ * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge.
+ */
+
+#include "xc_private.h"
+
+int xc_sedf_domain_set(int xc_handle,
+                          u32 domid, u64 period, u64 slice)
+{
+    dom0_op_t op;
+    struct sedf_adjdom *p = &op.u.adjustdom.u.sedf;
+
+    op.cmd = DOM0_ADJUSTDOM;
+    op.u.adjustdom.domain  = (domid_t)domid;
+    op.u.adjustdom.sched_id = SCHED_SEDF;
+    op.u.adjustdom.direction = SCHED_INFO_PUT;
+
+    p->period   = period;
+    p->slice    = slice;
+    return do_dom0_op(xc_handle, &op);
+}
+
+int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice)
+{
+    dom0_op_t op;
+    int ret;
+    struct sedf_adjdom *p = &op.u.adjustdom.u.sedf;
+
+    op.cmd = DOM0_ADJUSTDOM;    
+    op.u.adjustdom.domain = (domid_t)domid;
+    op.u.adjustdom.sched_id = SCHED_SEDF;
+    op.u.adjustdom.direction = SCHED_INFO_GET;
+
+    ret = do_dom0_op(xc_handle, &op);
+
+    *period   = p->period;
+    *slice    = p->slice;
+    return ret;
+}
index 2dd8680b4f016cb5c9c0f2e1eafcc493344cd2e1..55fabf9683b2468e4df8e24af4ef2418735cdd4a 100644 (file)
@@ -758,6 +758,50 @@ static PyObject *pyxc_rrobin_global_set(PyObject *self,
     return zero;
 }
 
+static PyObject *pyxc_sedf_domain_set(PyObject *self,
+                                         PyObject *args,
+                                         PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    u32 domid;
+    u64 period, slice;
+    
+    static char *kwd_list[] = { "dom", "period", "slice", NULL };
+    
+    if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLL", kwd_list, &domid,
+                                     &period, &slice) )
+        return NULL;
+   
+    if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
+}
+
+static PyObject *pyxc_sedf_domain_get(PyObject *self,
+                                         PyObject *args,
+                                         PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+    u32 domid;
+    u64 period, slice;
+        
+    static char *kwd_list[] = { "dom", NULL };
+
+    if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) )
+        return NULL;
+    
+    if ( xc_sedf_domain_get( xc->xc_handle, domid, &period,
+                                &slice) )
+        return PyErr_SetFromErrno(xc_error);
+
+    return Py_BuildValue("{s:i,s:L,s:L}",
+                         "domain",  domid,
+                         "period",  period,
+                         "slice",   slice);
+}
+
 static PyObject *pyxc_shadow_control(PyObject *self,
                                      PyObject *args,
                                      PyObject *kwds)
@@ -984,6 +1028,26 @@ static PyMethodDef pyxc_methods[] = {
       "Get Round Robin scheduler settings\n"
       "Returns [dict]:\n"
       " slice  [long]: Scheduler time slice.\n" },    
+    
+    { "sedf_domain_set",
+      (PyCFunction)pyxc_sedf_domain_set,
+      METH_KEYWORDS, "\n"
+      "Set the scheduling parameters for a domain when running with Atropos.\n"
+      " dom      [int]:  domain to set\n"
+      " period   [long]: domain's scheduling period\n"
+      " slice    [long]: domain's slice per period\n"
+      "Returns: [int] 0 on success; -1 on error.\n" },
+
+    { "sedf_domain_get",
+      (PyCFunction)pyxc_sedf_domain_get,
+      METH_KEYWORDS, "\n"
+      "Get the current scheduling parameters for a domain when running with\n"
+      "the Atropos scheduler."
+      " dom      [int]: domain to query\n"
+      "Returns:  [dict]\n"
+      " domain   [int]: domain ID\n"
+      " period   [long]: scheduler period\n"
+      " slice    [long]: CPU reservation per period\n"},
 
     { "evtchn_alloc_unbound", 
       (PyCFunction)pyxc_evtchn_alloc_unbound,
index 8290165412f48a77c595a2efa9ad4f4e9eb23cd3..0d5ac106f2c0f9f955572a362759146d57f3d828 100644 (file)
@@ -272,6 +272,12 @@ class Xend:
                               'latency' : latency,
                               'xtratime': xtratime })
 
+    def xend_domain_cpu_sedf_set(self, id, period, slice):
+        return self.xendPost(self.domainurl(id),
+                             {'op'      : 'cpu_sedf_set',
+                              'period'  : period,
+                              'slice'   : slice })
+
     def xend_domain_maxmem_set(self, id, memory):
         return self.xendPost(self.domainurl(id),
                              { 'op'     : 'maxmem_set',
index fc53b4de03cea3f097e8e1dd7b85563e1c359490..fc5fba1efe526f9cd01e3edab04de1665b2d2729 100644 (file)
@@ -659,6 +659,24 @@ class XendDomain:
             return xc.atropos_domain_get(dominfo.dom)
         except Exception, ex:
             raise XendError(str(ex))
+    
+    def domain_cpu_sedf_set(self, id, period, slice):
+        """Set Atropos scheduler parameters for a domain.
+        """
+        dominfo = self.domain_lookup(id)
+        try:
+            return xc.sedf_domain_set(dominfo.dom, period, slice)
+        except Exception, ex:
+            raise XendError(str(ex))
+
+    def domain_cpu_sedf_get(self, id):
+        """Get Atropos scheduler parameters for a domain.
+        """
+        dominfo = self.domain_lookup(id)
+        try:
+            return xc.sedf_domain_get(dominfo.dom)
+        except Exception, ex:
+            raise XendError(str(ex))
 
     def domain_device_create(self, id, devconfig):
         """Create a new device for a domain.
index c06b260ce115c503331471a97ee0d760cbe6995f..46868f859c1157015dfd38ed753041ef52606550 100644 (file)
@@ -132,6 +132,14 @@ class SrvDomain(SrvDir):
                      ['xtratime', 'int']])
         val = fn(req.args, {'dom': self.dom.id})
         return val
+    
+    def op_cpu_sedf_set(self, op, req):
+        fn = FormFn(self.xd.domain_cpu_sedf_set,
+                    [['dom', 'str'],
+                     ['period', 'int'],
+                     ['slice', 'int']])
+        val = fn(req.args, {'dom': self.dom.id})
+        return val
 
     def op_maxmem_set(self, op, req):
         fn = FormFn(self.xd.domain_maxmem_set,
index e7454e507af0912be7af0c743e517cfa48660c8e..845e475a9c59675235d0debdd8632c35040429c4 100644 (file)
@@ -587,6 +587,23 @@ class ProgRrobin(Prog):
 
 xm.prog(ProgRrobin)
 
+class ProgSedf(Prog):
+    group = 'scheduler'
+    name= "sedf"
+    info = """Set simple EDF parameters."""
+
+    def help(self, args):
+        print args[0], "DOM PERIOD SLICE"
+        print "\nSet simple EDF parameters."
+
+    def main(self, args):
+        if len(args) != 4: self.err("%s: Invalid argument(s)" % args[0])
+        dom = args[1]
+        v = map(int, args[2:4])
+        server.xend_domain_cpu_sedf_set(dom, *v)
+
+xm.prog(ProgSedf)
+
 class ProgInfo(Prog):
     group = 'host'
     name = "info"
diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c
new file mode 100644 (file)
index 0000000..a85e112
--- /dev/null
@@ -0,0 +1,505 @@
+/****************************************************************************
+ * Simple EDF scheduler for xen
+ *
+ * by Stephan Diestelhorst (C)  2004 Cambridge University
+ * based on code by Mark Williamson (C) 2004 Intel Research Cambridge
+ */
+
+#include <xen/sched.h>
+#include <xen/sched-if.h>
+#include <public/sched_ctl.h>
+#include <xen/ac_timer.h>
+#include <xen/softirq.h>
+#include <xen/time.h>
+#include <xen/slab.h>
+
+#define SEDFLEVEL 0
+#define PRINT(_f, _a...)  \
+if ((_f)<=SEDFLEVEL) printk(_a );
+
+/*
+       TODO:
+       TESTING!
+       implement stylish features!
+       tracing instead of PRINTs
+*/
+
+
+#define TRC_SEDF 0xBEEF0000
+
+struct sedf_dom_info
+{
+       struct domain           *owner;
+       struct list_head        list;
+       
+       //Parameters for EDF
+       s_time_t                period;         //=(relative deadline)
+       s_time_t                slice;          //=worst case execution time
+       int                     extratime;
+       //Bookkeeping
+       s_time_t                absdead;
+       s_time_t                sched_start;
+       s_time_t                cputime;
+       s_time_t                absblock;
+       //Statistics
+       s_time_t                block_time_tot;
+       s_time_t                penalty_time_tot;
+       
+};
+
+struct sedf_cpu_info {
+       struct list_head runnableq;
+       struct list_head waitq;
+};
+
+#define DOM_INFO(d)    ((struct sedf_dom_info *)((d)->sched_priv))
+#define CPU_INFO(cpu)  ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv)
+#define LIST(d)                (&DOM_INFO(d)->list)
+#define RUNQ(cpu)      (&CPU_INFO(cpu)->runnableq)
+#define WAITQ(cpu)     (&CPU_INFO(cpu)->waitq)
+#define IDLETASK(cpu)  ((struct domain *)schedule_data[cpu].idle)
+
+static xmem_cache_t *dom_info_cache;
+
+/*static inline void __add_to_runqueue_head(struct domain *d)
+{
+    list_add(RUNLIST(d), RUNQUEUE(d->processor));
+}
+
+static inline void __add_to_runqueue_tail(struct domain *d)
+{
+    list_add_tail(RUNLIST(d), RUNQUEUE(d->processor));
+}*/
+
+static inline void __del_from_queue(struct domain *d)
+{
+    struct list_head *list = LIST(d);
+    list_del(list);
+    list->next = NULL;
+}
+
+/* adds a domain to the queue of processes which wait for the beginning of the next period
+ * this list is therefore sortet by this time, which is simply absol. deadline - period
+ */ 
+static inline void __add_to_waitqueue_sort(struct domain *d) {
+       struct list_head     *cur;
+       struct sedf_dom_info *curinf;
+       
+       PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,DOM_INFO(d)->absdead - DOM_INFO(d)->period);    
+       //iterate through all elements to find our "hole"
+       list_for_each(cur,WAITQ(d->processor)){
+               curinf = list_entry(cur,struct sedf_dom_info,list);
+               if ( DOM_INFO(d)->absdead - DOM_INFO(d)->period < curinf->absdead - curinf->period)
+                       break;
+               else
+                       PRINT(4,"\tbehind domain %i (bop= %llu)\n",curinf->owner->id,curinf->absdead - curinf->period);
+       }
+       //cur now contains the element, before which we'll enqueue
+       PRINT(3,"\tlist_add to %x\n",cur->prev);
+       list_add(LIST(d),cur->prev);
+
+}
+
+/* adds a domain to the queue of processes which have started their current period and are
+ * runnable (i.e. not blocked, dieing,...). The first element on this list is running on the processor,
+ * if the list is empty the idle task will run. As we are implementing EDF, this list is sorted by 
+ * deadlines.
+ */ 
+static inline void __add_to_runqueue_sort(struct domain *d) {
+       struct list_head     *cur;
+       struct sedf_dom_info *curinf;
+
+       PRINT(3,"Adding domain %i (deadl= %llu) to runq\n",d->id,DOM_INFO(d)->absdead); 
+       //iterate through all elements to find our "hole"
+       list_for_each(cur,RUNQ(d->processor)){
+               curinf = list_entry(cur,struct sedf_dom_info,list);
+               if (DOM_INFO(d)->absdead < curinf->absdead)
+                       break;
+               else
+                       PRINT(4,"\tbehind domain %i (deadl= %llu)\n",curinf->owner->id,curinf->absdead);
+       }
+       //cur now contains the element, before which we'll enqueue
+       PRINT(3,"\tlist_add to %x\n",cur->prev);
+       list_add(LIST(d),cur->prev);
+
+}
+static inline int __task_on_queue(struct domain *d) {
+       return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d)));
+}
+
+/* Initialises the queues and creates the domain info cache */
+static int sedf_init_scheduler() {
+       int i;
+       PRINT(2,"sedf_init_scheduler was called\n");
+       
+       for ( i = 0; i < NR_CPUS; i++ ) {
+               schedule_data[i].sched_priv = xmalloc(sizeof(struct sedf_cpu_info));
+               if ( schedule_data[i].sched_priv == NULL )
+                       return -1;
+               INIT_LIST_HEAD(WAITQ(i));
+               INIT_LIST_HEAD(RUNQ(i));
+       }
+       
+       dom_info_cache = xmem_cache_create(
+               "SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL);
+       if ( dom_info_cache == NULL )
+       {
+               printk("Could not allocate SLAB cache.\n");
+               return -1;
+       }
+       
+       return 0;                                                                
+}
+
+/* Allocates memory for per domain private scheduling data*/
+static int sedf_alloc_task(struct domain *d) {
+       PRINT(2,"sedf_alloc_task was called, domain-id %i\n",d->id);
+       if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL )
+               return -1;
+       memset(d->sched_priv, 0, sizeof(struct sedf_dom_info));
+       return 0;
+}
+
+/* Setup the sedf_dom_info */
+static void sedf_add_task(struct domain *d)
+{
+       //s_time_t now=NOW();
+       struct sedf_dom_info *inf=DOM_INFO(d);
+       inf->owner = d;
+       
+       PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id);
+       if (d->id==0) {
+               //set dom0 to something useful to boot the machine
+               inf->period = MILLISECS(20);
+               inf->slice  = MILLISECS(15);
+               inf->absdead= 0;
+       }
+       else {
+               //other domains don't get any execution time at all in the beginning!
+               inf->period = MILLISECS(20);
+               inf->slice  = 0;
+               inf->absdead= 0;
+       }
+       INIT_LIST_HEAD(&(inf->list));
+}
+
+/* Frees memory used by domain info */
+static void sedf_free_task(struct domain *d)
+{
+       PRINT(2,"sedf_free_task was called, domain-id %i\n",d->id);
+       ASSERT(d->sched_priv != NULL);
+       xmem_cache_free(dom_info_cache, d->sched_priv);
+}
+
+/* Initialises idle task */
+static int sedf_init_idle_task(struct domain *d) {
+       PRINT(2,"sedf_init_idle_task was called, domain-id %i\n",d->id);
+       if ( sedf_alloc_task(d) < 0 )
+               return -1;
+       
+       sedf_add_task(d);
+       DOM_INFO(d)->absdead=0;
+       set_bit(DF_RUNNING, &d->flags);
+       //the idle task doesn't have to turn up on any list...
+       return 0;
+}
+
+#define MIN(x,y) (((x)<(y))?(x):(y))
+/* Main scheduling function
+ * Reasons for calling this function are:
+ * -timeslice for the current period used up
+ * -domain on waitqueue has started it's period*/
+static task_slice_t sedf_do_schedule(s_time_t now)
+{
+       struct sedf_dom_info *inf   = DOM_INFO(current);
+       int                   cpu   = current->processor;
+       struct list_head     *runq  = RUNQ(cpu);
+       struct list_head     *waitq = WAITQ(cpu);
+       struct list_head     *cur,*tmp;
+       struct sedf_dom_info *curinf;
+       task_slice_t          ret;
+       
+       //first of all update the domains cputime
+       inf->cputime += now - inf->sched_start;
+       
+       //scheduling decisions, which don't involve the running domain
+       if (is_idle_task(inf->owner))
+               goto check_waitq;                               //idle task doesn't get scheduled on the runq
+       if (!((inf->cputime >= inf->slice) || !domain_runnable(inf->owner)))
+               goto check_waitq;                               //nothing to do with the running task
+       
+       //remove tasks that can't run
+       __del_from_queue(inf->owner);
+               
+       //manage bookkeeping
+       if (inf->cputime >= inf->slice) {
+               inf->absdead += inf->period;
+               inf->cputime -= inf->slice;
+               if (inf->cputime<0) inf->cputime = 0;
+       }
+       if (inf->absdead<now);
+               //printk("Domain %i exceeded it't deadline!!!! (now: %llu ddl: %llu)\n",current->id,now,inf->absdead);
+       //add a runnable domain to the waitqueue                
+       if (domain_runnable(inf->owner))
+               __add_to_waitqueue_sort(inf->owner);
+       else
+               inf->absblock=now;
+               
+check_waitq:
+       //check for the first elements of the waitqueue, whether their next period has already started
+       list_for_each_safe(cur,tmp,waitq) {
+               curinf = list_entry(cur,struct sedf_dom_info,list);
+               if (curinf->absdead - curinf->period<=now) {
+                       __del_from_queue(curinf->owner);
+                       __add_to_runqueue_sort(curinf->owner);
+               }
+               else
+                       break;
+       }
+       
+       //process the runq
+       list_for_each_safe(cur,tmp,runq) {
+               curinf = list_entry(cur,struct sedf_dom_info,list);
+               if (unlikely(curinf->slice == 0)) {
+                       //special treatment of elements with empty slice
+                       __del_from_queue(curinf->owner);
+                       curinf->absdead += curinf->period;
+                       __add_to_waitqueue_sort(curinf->owner);
+               }
+               else
+                       if (unlikely((curinf->absdead < now) || (curinf->cputime > curinf->slice))) {
+                               //we missed the deadline or the slice was already finished... might hapen because of dom_adj.
+                               //printk("Ouch! Domain %i missed deadline %llu\n",curinf->owner->id,curinf->absdead);
+                               __del_from_queue(curinf->owner);
+                               curinf->absdead += ((now - curinf->absdead) / curinf->period + 1) * curinf->period;             
+                                       //force start of period to be in future!
+                               //curinf->absdead += curinf->period;
+                               curinf->cputime = 0;
+                               __add_to_runqueue_sort(curinf->owner);
+                       }
+                       else
+                               break;
+       }
+       
+       //now simply pick the first domain from the runqueue
+       struct sedf_dom_info *runinf, *waitinf;
+       
+       if (!list_empty(runq)) {
+               runinf   = list_entry(runq->next,struct sedf_dom_info,list);
+               ret.task = runinf->owner;
+               if (!list_empty(waitq)) {
+                       //rerun scheduler, when scheduled domain reaches it's end of slice or the first domain from the waitqueue gets ready
+                       waitinf  = list_entry(waitq->next,struct sedf_dom_info,list);
+                       ret.time = MIN(now + runinf->slice - runinf->cputime,waitinf->absdead - waitinf->period) - now;
+               }
+               else {
+                       ret.time = runinf->slice - runinf->cputime;
+               }
+       }
+       else {
+               //we have an empty runqueue => let the idle domain run and start the scheduler, when the next task becomes available
+               ret.task = IDLETASK(cpu);
+               if (!list_empty(waitq)) {
+                       waitinf = list_entry(waitq->next,struct sedf_dom_info,list);
+                       ret.time = (waitinf->absdead - waitinf->period) - now;
+               }
+               else {
+                       //this could porbably never happen, but one never knows...
+                       //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;)
+                       ret.time=SECONDS(1);
+               }
+       }
+       if (ret.time<0)
+               printk("Ouch! We are seriously BEHIND schedule! %lli\n",ret.time);
+       DOM_INFO(ret.task)->sched_start=now;
+       return ret;
+}
+
+static void sedf_sleep(struct domain *d) {
+       PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id);
+       if ( test_bit(DF_RUNNING, &d->flags) )
+               cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+       else if ( __task_on_queue(d) )
+               __del_from_queue(d);
+}
+
+/* This function wakes ifup a domain, i.e. moves them into the waitqueue
+ * things to mention are: admission control is taking place nowhere at
+ * the moment, so we can't be sure, whether it is safe to wake the domain
+ * up at all. Anyway, even if it is safe (total cpu usage <=100%) there are
+ * some considerations on when to allow the domain to wake up and have it's
+ * first deadline...
+ * I detected 3 cases, which could describe the possible behaviour of the scheduler,
+ * and I'll try to make them more clear:
+ *
+ * 1. Very conservative
+ *     -when a blocked domain unblocks, it is allowed to start execution at
+ *      the beginning of the next complete period
+ *      (D..deadline, R..running, B..blocking/sleeping, U..unblocking/waking up
+ *
+ *      DRRB_____D__U_____DRRRRR___D________ ... 
+ *
+ *     -this causes the domain to miss a period (and a deadlline)
+ *     -doesn't disturb the schedule at all
+ *     -deadlines keep occuring isochronous
+ *
+ * 2. Conservative Part 1
+ *     -when a domain unblocks in the same period as it was blocked it unblocks and
+ *      may consume the rest of it's original time-slice minus the time it was blocked
+ *      (assume period=9, slice=5)
+ *
+ *      DRB_UR___DRRRRR___D...
+ *
+ *     -this also doesn't disturb scheduling, but might lead to the fact, that the domain
+ *      can't finish it's workload in the period
+ *
+ *    Part 2a
+ *     -it is obvious that such behaviour, applied when then unblocking is happening in
+ *      later domains,tinyvnc works fine aswell
+ *
+ *      DRB______D___UR___D... 
+ *
+ *    Part 2b
+ *     -if one needs the full slice in the next period, it is necessary to treat the unblocking
+ *      time as the start of the new period, i.e. move the deadline further back (later)
+ *     -this doesn't disturb scheduling as well, because for EDF periods can be treated as minimal
+ *      inter-release times and scheduling stays correct, when deadlines are kept relative to the time
+ *      the process unblocks
+ *
+ *      DRB______D___URRRR___D...
+ *                       (D) 
+ *     -problem: deadlines don't occur isochronous anymore
+ *
+ * 3. Unconservative (i.e. incorrect)
+ *     -to boost the performance of I/O dependent domains it would be possible to put the domain into
+ *      the runnable queue immediately, and let it run for the remainder of the slice of the current period
+ *      (or even worse: allocate a new full slice for the domain) (and probably tweaking the deadline/slice even more)
+ *     -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b
+ */
+void sedf_wake(struct domain *d) {
+       //for the first try just implement the "very conservative" way of waking domains up
+       s_time_t              now = NOW();
+       struct sedf_dom_info* inf = DOM_INFO(d);
+       
+       PRINT(3,"sedf_wake was called, domain-id %i\n",d->id);
+       
+       if (unlikely(is_idle_task(d)))
+               return;
+       
+       if ( unlikely(__task_on_queue(d)) ) {
+               PRINT(3,"\tdomain %i is already in some queue\n",d->id);
+               return;
+       }
+       
+       //very conservative way of unblocking
+       //make sure that the start of the period for this
+       //domain is happening in the future
+       PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now);
+       inf->absdead += ((now - inf->absdead) / inf->period+1)*inf->period;
+       PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now);
+       
+       __add_to_waitqueue_sort(d);
+       PRINT(3,"added to waitq\n");    
+       
+       //TODO: Implement more fancy unblocking schemes!
+       /*if (now < inf->absdead) {
+               //short blocking
+       }
+       else {
+               //long blocking 
+       }*/
+       
+       //do some statistics here...
+       if (inf->absblock!=0) {
+               inf->block_time_tot += now - inf->absblock;
+               inf->penalty_time_tot += (inf->absdead - inf-> period) - inf->absblock;
+               /*if (DOM_INFO(d)->block_time_tot)
+                       PRINT(3,"penalty: %lu\n",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot);*/
+       }
+       /*if ( is_idle_task(schedule_data[d->processor].curr)) {
+               cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+               return;
+       }*/
+       
+       //check whether the awakened task needs to get scheduled before the next sched. decision
+       if  (inf->absdead - inf->period < schedule_data[d->processor].s_timer.expires)
+               cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+}
+
+
+/* This could probably be a bit more specific!*/
+static void sedf_dump_domain(struct domain *d) {
+       printk("%u has=%c ", d->id,
+               test_bit(DF_RUNNING, &d->flags) ? 'T':'F');
+       printk("c=%llu p=%llu sl=%llu ddl=%llu", d->cpu_time,DOM_INFO(d)->period,DOM_INFO(d)->slice,DOM_INFO(d)->absdead);
+       if (DOM_INFO(d)->block_time_tot!=0)
+               printf(" penalty: %lu",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot);
+       printf("\n");
+}
+
+static void sedf_dump_cpu_state(int i)
+{
+    struct list_head *list, *queue;
+    int loop = 0;
+    struct sedf_dom_info *d_inf;
+
+    printk("now=%llu\n",NOW());
+    queue = RUNQ(i);
+    printk("RUNQ rq %lx   n: %lx, p: %lx\n",  (unsigned long)queue,
+        (unsigned long) queue->next, (unsigned long) queue->prev);
+    list_for_each ( list, queue )
+    {
+        printk("%3d: ",loop++);
+        d_inf = list_entry(list, struct sedf_dom_info, list);
+        sedf_dump_domain(d_inf->owner);
+    }
+    
+    queue = WAITQ(i);
+    printk("\nWAITQ rq %lx   n: %lx, p: %lx\n",  (unsigned long)queue,
+        (unsigned long) queue->next, (unsigned long) queue->prev);
+    list_for_each ( list, queue )
+    {
+        printk("%3d: ",loop++);
+        d_inf = list_entry(list, struct sedf_dom_info, list);
+        sedf_dump_domain(d_inf->owner);
+    }
+
+}
+
+/* set or fetch domain scheduling parameters */
+static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) {
+       PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu new slice %llu\n",p->id,cmd->u.sedf.period,cmd->u.sedf.slice);
+       if ( cmd->direction == SCHED_INFO_PUT )
+       {
+               /* sanity checking! */
+               if(cmd->u.sedf.slice > cmd->u.sedf.period )
+               return -EINVAL;
+               
+               DOM_INFO(p)->period   = cmd->u.sedf.period;
+               DOM_INFO(p)->slice    = cmd->u.sedf.slice;
+       }
+       else if ( cmd->direction == SCHED_INFO_GET )
+       {
+               cmd->u.sedf.period   = DOM_INFO(p)->period;
+               cmd->u.sedf.slice    = DOM_INFO(p)->slice;
+       }
+       PRINT(2,"sedf_adjdom_finished\n");
+       return 0;
+}
+
+struct scheduler sched_sedf_def = {
+    .name     = "Simple EDF Scheduler",
+    .opt_name = "sedf",
+    .sched_id = SCHED_SEDF,
+    
+    .init_idle_task = sedf_init_idle_task,
+    .alloc_task     = sedf_alloc_task,
+    .add_task       = sedf_add_task,
+    .free_task      = sedf_free_task,
+    .init_scheduler = sedf_init_scheduler,
+    .do_schedule    = sedf_do_schedule,
+    .dump_cpu_state = sedf_dump_cpu_state,
+    .sleep          = sedf_sleep,
+    .wake           = sedf_wake,
+    .adjdom         = sedf_adjdom,
+};
index 4aceef7d2ac02402d6b76af4ed12e4be0d56c396..27e87cd0f5673c932ac65054325cc5918975b9af 100644 (file)
@@ -68,10 +68,12 @@ schedule_data_t schedule_data[NR_CPUS];
 extern struct scheduler sched_bvt_def;
 extern struct scheduler sched_rrobin_def;
 extern struct scheduler sched_atropos_def;
+extern struct scheduler sched_sedf_def;
 static struct scheduler *schedulers[] = { 
     &sched_bvt_def,
     &sched_rrobin_def,
     &sched_atropos_def,
+    &sched_sedf_def,
     NULL
 };
 
@@ -285,7 +287,7 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd)
 
     if ( cmd->sched_id != ops.sched_id )
         return -EINVAL;
-
+    
     if ( cmd->direction != SCHED_INFO_PUT && cmd->direction != SCHED_INFO_GET )
         return -EINVAL;
 
index bd6a7175219bffafb109fbff21a13cb3f8ff6a6a..f2b9722a4de35442835ea5da690d405bb6392a5e 100644 (file)
@@ -11,6 +11,7 @@
 #define SCHED_BVT      0
 #define SCHED_ATROPOS  2
 #define SCHED_RROBIN   3
+#define SCHED_SEDF     4
 
 /* these describe the intended direction used for a scheduler control or domain
  * command */
@@ -64,6 +65,15 @@ struct sched_adjdom_cmd
             u64 latency;    /* 32 */
             u32 xtratime;   /* 36 */
         } PACKED atropos;
+        
+       struct sedf_adjdom
+        {
+            u64 period;     /* 16 */
+            u64 slice;      /* 24 */
+            u64 dummy1;     /* 32 */
+            u32 dummy2;     /* 36 */
+        } PACKED sedf;
+
     } PACKED u;
 } PACKED; /* 40 bytes */